package threadDemo;

import java.util.concurrent.Semaphore;

/***
 * 思路：三个线程对应三个Semaphore，三个Semaphore维护一个Permit。
 * 当前线程通过对应的Semaphore获取Permit，执行打印，并通过下一个线程对应的Semaphore释放Permit。
 * 类似于Permit在当前的线程对应的Semaphore中，传递到了下一个线程对应的Semaphore中。
 * 下一个线程通过对应的Semaphore获取Permit，继续执行……循环10次。
 *
 * 效率：每个线程使用一个Semaphore，一个Permit在不同的Semaphore之间循环传递，
 * 当前线程消费完Permit后，无法立即进行下一次打印，而下一个线程使用的Semaphore刚好获取到了Permit，
 * 从而使线程可以交替执行。不需要额外的线程轮流状态state字段。代码简洁，效率高。
 *
 * acquire与release之间的关系：在实现中不包含真正的许可对象，并且Semaphore也不会将许可与线程关联起来，
 * 因此在一个线程中获得的许可可以在另一个线程中释放。
 * 可以将acquire操作视为是消费一个许可，而release操作是创建一个许可，Semaphore并不受限于它在创建时的初始许可数量。
 * 也就是说acquire与release并没有强制的一对一关系，release一次就相当于新增一个许可，
 * 许可的数量可能会由于没有与acquire操作一对一而导致超出初始化时设置的许可个数。
 */
public class SemaphorePrintDemo {
    public static void main(String[] args) {
        printUseSemaphore demo = new printUseSemaphore();
        new Thread(() -> demo.printA()).start();
        new Thread(() -> demo.printB()).start();
        new Thread(() -> demo.printC()).start();
    }


    static class printUseSemaphore {
        Semaphore semaphoreA = new Semaphore(1);
        Semaphore semaphoreB = new Semaphore(0);
        Semaphore semaphoreC = new Semaphore(0);

        public void print(int loopNum, String str, Semaphore cur, Semaphore next) {
            try {
                cur.acquire();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            for (int i = 0; i < loopNum; i++) {
                System.out.print(str);
            }
            next.release();
        }

        public void printA() {
            print(1, "A", semaphoreA, semaphoreB);
        }

        public void printB() {
            print(3, "B", semaphoreB, semaphoreC);
        }

        public void printC() {
            print(5, "C", semaphoreC, semaphoreA);
        }
    }
}
